package com.dj.product.k2faas.jpa.view;

import com.dj.product.k2faas.jpa.dto.QueryArg;
import com.dj.product.k2faas.jpa.sqlgenerator.SqlGenerator;
import com.dj.product.k2faas.common.exception.NotFoundException;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by 丁建 on 2025/9/23 09:49
 *
 * @author 丁建
 */
@AllArgsConstructor
public class JdbcCommonView implements CommonView {

    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    private SqlGenerator sqlGenerator;

    @Override
    public int update(String sqlTemplate, QueryArg queryArg) {
        String sql = this.sqlGenerator.getQueryBasicSql(sqlTemplate, queryArg);
        return this.namedParameterJdbcTemplate.update(sql, queryArg.getArgs());
    }

    @Override
    public <T> Page<T> findAllByPage(String sqlTemplate, QueryArg queryArg, Class<T> tClass) {
        var basicSql = sqlGenerator.getQueryBasicSql(sqlTemplate, queryArg);
        var countSql = sqlGenerator.getCountSql(basicSql);
        List<T> list = null;

        var parameterSource = new K2MapSqlParameterSource(queryArg.getArgs());

        var total = namedParameterJdbcTemplate.queryForObject(countSql, parameterSource, Integer.class);
        if (total == 0) {
            return new PageImpl<>(Collections.emptyList(), queryArg.getPage(), total);
        }

        var querySql = sqlGenerator.getPagedSql(basicSql, queryArg.getPage().getPageNumber(), queryArg.getPage().getPageSize());
        if (tClass == Map.class || tClass == Set.class) {
            list = namedParameterJdbcTemplate.queryForList(querySql, parameterSource, tClass);
        } else if (tClass == String.class || tClass == Integer.class || tClass == Long.class || tClass == Double.class || tClass == Float.class
                   || tClass == BigDecimal.class) {
            list = namedParameterJdbcTemplate.queryForList(querySql, parameterSource, tClass);
        } else {
            list = namedParameterJdbcTemplate.query(querySql, parameterSource, new BeanPropertyRowMapper<>(tClass));
        }
        if (queryArg.getPage().getPageNumber() * queryArg.getPage().getPageSize() > total) {
            var page = PageRequest.of(total / queryArg.getPage().getPageSize(), queryArg.getPage().getPageSize());
            return new PageImpl<>(list, page, total);
        } else {
            return new PageImpl<>(list, queryArg.getPage(), total);
        }

    }

    @Override
    public <T> T findOne(String sqlTemplate, QueryArg queryArg, Class<T> tClass, String errorMessage) {
        var result = findOne(sqlTemplate, queryArg, tClass);
        if (result == null) {
            throw new NotFoundException(errorMessage);
        }

        return result;
    }

    @Override
    public <T> Optional<T> tryFindOne(String sqlTemplate, QueryArg queryArg, Class<T> tClass) {
        return Optional.ofNullable(findOne(sqlTemplate, queryArg, tClass));
    }

    @Override
    public <T> T findOne(String sqlTemplate, QueryArg queryArg, Class<T> tClass) {
        var basicSql = sqlGenerator.getQueryBasicSql(sqlTemplate, queryArg);
        var fetchSql = sqlGenerator.getFetchSql(basicSql);
        var parameterSource = new K2MapSqlParameterSource(queryArg.getArgs());

        T t = null;
        List<T> tList = null;
        if (tClass == Map.class || tClass == Set.class) {
            tList = namedParameterJdbcTemplate.queryForList(fetchSql, parameterSource, tClass);
        } else if (tClass == String.class || tClass == Integer.class || tClass == Long.class || tClass == Double.class || tClass == Float.class
                   || tClass == BigDecimal.class) {
            tList = namedParameterJdbcTemplate.queryForList(fetchSql, parameterSource, tClass);
        } else {
            tList = namedParameterJdbcTemplate.query(fetchSql, parameterSource, new BeanPropertyRowMapper<>(tClass));
        }

        if (tList.isEmpty()) {
            t = null;
        } else {
            t = tList.get(0);
        }
        return t;
    }

    @Override
    public <T> List<T> findAll(String sqlTemplate, QueryArg queryArg, Class<T> tClass) {
        var basicSql = sqlGenerator.getQueryBasicSql(sqlTemplate, queryArg);
        var parameterSource = new K2MapSqlParameterSource(queryArg.getArgs());

        if (tClass == Map.class || tClass == Set.class) {
            return namedParameterJdbcTemplate.queryForList(basicSql, parameterSource, tClass);
        } else if (tClass == String.class || tClass == Integer.class || tClass == Long.class || tClass == Double.class || tClass == Float.class
                   || tClass == BigDecimal.class) {
            return namedParameterJdbcTemplate.queryForList(basicSql, parameterSource, tClass);
        } else {
            return namedParameterJdbcTemplate.query(basicSql, parameterSource, new BeanPropertyRowMapper<>(tClass));
        }
    }
}
